use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;

#[derive(Default)]
struct VertexBuffers {
    // 簇图标
    position_buffer_data: Vec<f32>,
    tex_coord_buffer_data: Vec<f32>,
    opacity_buffer_data: Vec<f32>,
    // 簇颜色
    text_position_data: Vec<f32>,
    text_tex_coord_data: Vec<f32>,
    // 辅助数据
    sprites_keys: Vec<String>,
    text_keys: Vec<String>,
}

impl VertexBuffers {
    // 清空缓冲区，为下一帧做准备
    fn clear(&mut self) {
        self.position_buffer_data.clear();
        self.tex_coord_buffer_data.clear();
        self.opacity_buffer_data.clear();
        self.text_position_data.clear();
        self.text_tex_coord_data.clear();
        self.sprites_keys.clear();
        self.text_keys.clear();
    }
}

#[derive(Deserialize)]
struct ClusterToDraw {
    key: String,
    text_key: String, // JS 预先准备好文本 key
    center_x: f64,
    center_y: f64,
    opacity: f32,
}
// 定义从 JS 传入的图集 UV 坐标
#[derive(Deserialize)]
struct AtlasBin {
    tl: [f32; 2], // top-left [u1,v2]
    br: [f32; 2], // bottom-right [u2,v1]
}

// 定义返回给 JS 的指针结构
#[derive(Serialize)]
struct BufferPointers {
    position_offset: usize,
    position_len: usize,
    tex_coord_offset: usize,
    tex_coord_len: usize,
    opacity_offset: usize,
    opacity_len: usize,

    text_position_offset: usize,
    text_position_len: usize,
    text_tex_coord_offset: usize,
    text_tex_coord_len: usize,
}

static mut SHARED_BUFFERS: Option<VertexBuffers> = None;

#[wasm_bindgen]
pub fn init_buffers() {
    unsafe {
        if SHARED_BUFFERS.is_none() {
            SHARED_BUFFERS = Some(VertexBuffers::default());
        }
    }
}

#[wasm_bindgen]
pub fn generate_vertex_buffers(
    clusters_js: JsValue,
    sprite_atlas_js: JsValue,
    text_atlas_js: JsValue,
    sprite_width_map_js: JsValue,
    sprite_height_map_js: JsValue,
    draw_cluster_text: bool,
    dpr: f32,
) -> Result<JsValue, JsValue> {
    // 获取或初始化全局缓冲区
    let buffers = unsafe {
        if SHARED_BUFFERS.is_none() {
            init_buffers();
        }
        SHARED_BUFFERS.as_mut().unwrap()
    };
    buffers.clear();
    let clusters: Vec<ClusterToDraw> = serde_wasm_bindgen::from_value(clusters_js)?;
    let sprite_atlas: HashMap<String, AtlasBin> = serde_wasm_bindgen::from_value(sprite_atlas_js)?;
    let text_atlas: HashMap<String, AtlasBin> = serde_wasm_bindgen::from_value(text_atlas_js)?;
    let sprite_widths: HashMap<String, f32> = serde_wasm_bindgen::from_value(sprite_width_map_js)?;
    let sprite_heights: HashMap<String, f32> =
        serde_wasm_bindgen::from_value(sprite_height_map_js)?;

    for cluster in clusters {
        let opacity = cluster.opacity;
        // 处理图标顶点
        let cluster_key = &cluster.key;
        if let Some(bin) = sprite_atlas.get(cluster_key) {
            let sprite_w = sprite_widths.get(cluster_key).cloned().unwrap_or(0.0);
            let sprite_h = sprite_heights.get(cluster_key).cloned().unwrap_or(0.0);
            let x = cluster.center_x as f32;
            let y = cluster.center_y as f32;

            // JS 中的 addPoint 逻辑
            let x1 = x;
            let y1 = y - sprite_h;
            let x2 = x1 + sprite_w;
            let y2 = y;

            // 6个顶点位置 (2个三角形 )
            buffers
                .position_buffer_data
                .extend_from_slice(&[x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]);
            // 6个不透明度
            buffers.opacity_buffer_data.extend_from_slice(&[opacity; 6]);
            // 6个纹理坐标
            let u1 = bin.tl[0];
            let v1 = bin.br[1];
            let u2 = bin.br[0];
            let v2 = bin.tl[1];
            buffers
                .tex_coord_buffer_data
                .extend_from_slice(&[u1, v1, u2, v1, u1, v2, u1, v2, u2, v1, u2, v2])
        }
        // 处理文本顶点
        if draw_cluster_text {
            if let Some(text_bin) = text_atlas.get(&cluster.text_key) {
                let text_w = (text_bin.br[0] - text_bin.tl[0]) * dpr;
                let text_h = (text_bin.tl[1] - text_bin.br[1]) * dpr;
                let x = cluster.center_x as f32
                    + sprite_widths.get(cluster_key).cloned().unwrap_or(0.0);
                let y = cluster.center_y as f32
                    - sprite_heights.get(cluster_key).cloned().unwrap_or(0.0);
                let w = text_w / 2.0;
                let h = text_h / 2.0;
                let x1 = x - w;
                let y1 = y - h;
                let x2 = x1 + w;
                let y2 = y1 + h;
                // 6个顶点位置 (2个三角形 )
                buffers
                    .text_position_data
                    .extend_from_slice(&[x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]);
                // 6个不透明度
                buffers.opacity_buffer_data.extend_from_slice(&[opacity; 6]);
                // 6个纹理坐标
                let u1 = text_bin.tl[0];
                let v1 = text_bin.br[1];
                let u2 = text_bin.br[0];
                let v2 = text_bin.tl[1];
                buffers
                    .text_tex_coord_data
                    .extend_from_slice(&[u1, v1, u2, v1, u1, v2, u1, v2, u2, v1, u2, v2])
            }
        }
    }
    let pointers = BufferPointers {
        position_offset: buffers.position_buffer_data.as_ptr() as usize,
        position_len: buffers.position_buffer_data.len(),
        tex_coord_offset: buffers.tex_coord_buffer_data.as_ptr() as usize,
        tex_coord_len: buffers.tex_coord_buffer_data.len(),
        opacity_offset: buffers.opacity_buffer_data.as_ptr() as usize,
        opacity_len: buffers.opacity_buffer_data.len(),

        text_position_offset: buffers.text_position_data.as_ptr() as usize,
        text_position_len: buffers.text_position_data.len(),
        text_tex_coord_offset: buffers.text_tex_coord_data.as_ptr() as usize,
        text_tex_coord_len: buffers.text_tex_coord_data.len(),
    };
    Ok(serde_wasm_bindgen::to_value(&pointers)?)
}
